
import {defer} from "../util/functions.js";
import {defineHandleButton} from "./buttons.js";
import {defineTabbingLoop} from "./tabbingLoop.js";
import {$} from "../util/seq.js";
import {siblingsOf} from "./selectors.js";

/**
 * @param container a one-element d3 selection
 * @param modalStore
 * @param {string} key
 */
export function defineModal(container, modalStore, key) {
    // UNDONE: rename defineModalDialog; separate out modal and dialog parts?
    // UNDONE: the name key is too generic. the key needs to refer to a boolean field that controls show/hide for the modal.

    const panel = container.select(".panel");
    const handle = modalStore.handle(key);

    container.on($`click`, event => {
        if (window.getSelection().toString() !== "") {
            // Don't dismiss the modal when the click is caused by text selection.
            event.stopPropagation();
            return;
        }
        handle.set(false);
    });

    // Do not allow tapping/clicking the panel to dismiss the modal.
    panel.on($`click`, event => event.stopPropagation());

    let focusTarget;

    function openModal(meta = {}) {
        // Hide all other modals
        Object.keys(modalStore.getAll()).forEach(k => k !== key && modalStore.set(k, false, {modalOpening: true}));
        // Show the modal
        container.property("hidden", false);
        // Make all siblings inert and blurred
        siblingsOf(container)
            .attr("inert", "");
            // .classed("blur", !isFirefox());  // FF 81 on Windows is not happy with blur on webgl layer
                                                // Actually, blur is bad on slow devices, so disable...
        // Move focus to the modal's primary element, but defer to allow inert changes to be processed
        // UNDONE: better way to control focus? maybe just focus on the dialog element itself?
        // UNDONE: when modal-focus class is not set, then this throws. Fix.
        defer(() => container.select(".modal-focus").node().focus());
        // Keep track of the element to return focus to when this modal closes.
        focusTarget = meta.actor;
    }

    function closeModal(meta = {}) {
        container.property("hidden", true);
        // Make all siblings not inert and not blurred
        siblingsOf(container)
            .attr("inert", null);
            // .classed("blur", false);
        if (focusTarget !== undefined && !meta.modalOpening) {
            // Move focus to the element which opened this dialog, but defer to allow inert changes to be processed
            const target = focusTarget;
            defer(() => target.focus());
        }
        focusTarget = undefined;
    }

    handle.on($`change`, (show, Ø, meta) => {
        return show === true ? openModal(meta) : closeModal(meta);
    });

    defineHandleButton(container.selectAll(".dialog-closer"), handle, false);
    defineTabbingLoop(panel);
}
